﻿using App.SqlSugar.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;


namespace App.SqlSugar
{
    public static class SqlSugarHelp
    {
        /// <summary>
        /// 迁移表
        /// </summary>
        /// <param name="db"></param>
        /// <param name="modelType"></param>
        public static void CreateDatabase(ISqlSugarClient db, Type modelType)
        {
            ////迁移表
            db.DbMaintenance.CreateDatabase();
            var types = modelType.Assembly.GetTypes();
            db.CodeFirst.InitTables(types);//根据types创建表
        }

        /// <summary>
        /// 组装sql链接字符串
        /// </summary>
        /// <param name="sqlType">数据类型</param>
        /// <param name="ip">ip</param>
        /// <param name="database">数据库</param>
        /// <param name="uid">账号</param>
        /// <param name="pwd">密码</param>
        /// <param name="port">端口</param>
        /// <returns></returns>
        public static string GetSqlDnc(DbType sqlType, string ip, string database, string uid, string pwd, string port = "")
        {
            var dns = string.Empty;
            if (sqlType == DbType.MySql)
            {
                if (string.IsNullOrWhiteSpace(port))
                {
                    port = "3306";
                }
                dns = $"server={ip};Database={database};Uid={uid};Pwd={pwd};Port={port};CharSet=utf8mb4;AllowLoadLocalInfile=true;";
            }
            else if (sqlType == DbType.SqlServer)
            {
                if (string.IsNullOrWhiteSpace(port))
                {
                    port = "1433";
                }
                dns = $"server={ip};uid={uid};pwd={pwd};database={database};Port={port};";
            }
            else if (sqlType == DbType.SqlServer)
            {
                if (string.IsNullOrWhiteSpace(port))
                {
                    port = "1433";
                }
                dns = $"PORT={port};DATABASE={database};HOST={ip};PASSWORD={pwd};USER ID={uid};MaxPoolSize=512;";
            }

            return dns;
        }
        /// <summary>
        /// 得到配置信息
        /// </summary>
        /// <param name="mySqlDns"></param>
        /// <param name="sqlLog"></param>
        /// <param name="warnSqlLog"></param>
        /// <param name="errorSqlLog"></param>
        /// <returns></returns>
        public static SqlSugarScope GetSqlSugarConfig(this IServiceCollection services, DbType sqlType, string mySqlDns, Action<string>? sqlLog = null,
                Action<double, string, string>? warnSqlLog = null, Action<string>? errorSqlLog = null)
        {
            var sqlSugar = new SqlSugarScope(new ConnectionConfig()
            {
                DbType = sqlType,
                ConnectionString = mySqlDns,
                IsAutoCloseConnection = true,   //是否自动关闭数据库
                ConfigureExternalServices = new ConfigureExternalServices
                {
                    // 表名不做处理
                    EntityNameService = (type, entity) =>
                    {
                        var attr = type.GetCustomAttribute<TableAttribute>();
                        if (attr != null)
                        {
                            entity.DbTableName = attr.Name;
                        }
                    },

                    // 列名
                    EntityService = (type, column) =>
                    {
                        // 设置主键
                        if (column.DbColumnName.ToLower() == "id")
                        {
                            column.IsPrimarykey = true;
                            column.IsIdentity = true;
                        }
                        // 主键
                        var keyAttr = type.GetCustomAttribute<KeyAttribute>();

                        if (keyAttr != null)
                        {
                            column.IsPrimarykey = true;
                            column.IsIdentity = true;
                        }

                        // 是否自动生成
                        var attr = type.GetCustomAttribute<DatabaseGeneratedAttribute>();
                        if (attr != null)
                        {
                            column.IsIdentity = attr.DatabaseGeneratedOption != 0;
                        }

                        // 设置默认值
                        var defaultVal = type.GetCustomAttribute<DefaultValueAttribute>();
                        if (defaultVal != null)
                        {
                            column.DefaultValue = defaultVal.Value?.ToString();
                        }

                        // 设置长度
                        var stringLengthVal = type.GetCustomAttribute<StringLengthAttribute>();
                        if (stringLengthVal != null)
                        {
                            column.Length = stringLengthVal.MaximumLength;
                        }

                        // 重命名字段
                        var columnAttr = type.GetCustomAttribute<ColumnAttribute>();
                        if (columnAttr != null && !string.IsNullOrWhiteSpace(columnAttr.Name))
                        {
                            column.DbColumnName = columnAttr.Name;
                        }
                        else
                        {
                            column.DbColumnName = column.DbColumnName[0].ToString().ToLower() + column.DbColumnName.Substring(1, column.DbColumnName.Count() - 1);
                        }

                        // 判断是否可空
                        // 支持？写法
                        if (column.IsPrimarykey == false && new NullabilityInfoContext().Create(type).WriteState is NullabilityState.Nullable)
                        {
                            column.IsNullable = true;
                        }
                        // 如果是string 设置为可空
                        if (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null)
                        {
                            column.IsNullable = true;
                        }
                    },

                },
            },
             db =>
             {
                 //每次上下文都会执行

                 //Sql超时 2分钟
                 db.Ado.CommandTimeOut = 60 * 2;

                 // 如果实现了接口IEntityIsDelete 就需要加上false
                 //全局过滤器
                 db.QueryFilter.AddTableFilter<IEntityIsDelete>(it => it.isDelete == false);

                 // 获取httpcontext 上下文
                 var serviceBuilder = services.BuildServiceProvider();
                 var httpContext = serviceBuilder.GetService<IHttpContextAccessor>();

                 // 获取上下文
                 var claims = httpContext.HttpContext.User.Claims;
                 var userId = claims.FirstOrDefault(p => p.Type == "userId")?.Value;
                 var groupId = claims.FirstOrDefault(p => p.Type == "groupId")?.Value;

                 if (!string.IsNullOrWhiteSpace(groupId))
                 {
                     db.QueryFilter.AddTableFilter<IEnTityGroupId<int>>(it => it.groupId == Convert.ToInt32(groupId));
                     db.QueryFilter.AddTableFilter<IEnTityGroupId<string>>(it => it.groupId == groupId);
                 }

                 //Claims.FirstOrDefault(p => p.Type == "userId")?.Value;

                 //sql执行前
                 db.Aop.OnLogExecuting = (sql, pars) =>
                 {
                     if (sqlLog != null)
                     {
                         sqlLog?.Invoke(sql);
                     }
                 };

                 // 数据curd事件
                 db.Aop.DataExecuting = (oldValue, entityInfo) =>
                 {
                     /*** 列级别事件：插入的每个列都会进事件 ***/
                     var type = entityInfo.OperationType;
                     var fieId = entityInfo.PropertyName.ToLower();

                     // 新增
                     if (type == DataFilterType.InsertByObject)
                     {
                         if (fieId == "createDt".ToLower())
                         {
                             entityInfo.SetValue(DateTime.Now);//修改CreateTime字段
                         }
                         if (fieId == "isDelete".ToLower())
                         {
                             entityInfo.SetValue(false);
                         }
                         if (fieId == "createId".ToLower())
                         {
                             if (!string.IsNullOrWhiteSpace(userId))
                             {
                                 entityInfo.SetValue(userId);
                             }
                         }
                     }
                     else if (type == DataFilterType.UpdateByObject)
                     {
                         if (fieId == "updateDt".ToLower())
                         {
                             entityInfo.SetValue(DateTime.Now);//修改CreateTime字段
                         }
                         if (fieId == "updateId".ToLower())
                         {
                             if (!string.IsNullOrWhiteSpace(userId))
                             {
                                 entityInfo.SetValue(userId);
                             }
                         }
                     }
                     else if (type == DataFilterType.DeleteByObject)
                     {
                         if (fieId == "isDelete".ToLower())
                         {
                             entityInfo.SetValue(true);
                         }
                     }
                 };

                 //SQL执行完
                 db.Aop.OnLogExecuted = (sql, p) =>
                 {
                     if (warnSqlLog != null)
                     {
                         var timeMill = db.Ado.SqlExecutionTime.TotalMilliseconds;

                         //执行时间超过1秒
                         if (timeMill > 2 * 1000)
                         {
                             //代码CS文件名
                             var fileName = db.Ado.SqlStackTrace.FirstFileName;
                             //代码行数
                             var fileLine = db.Ado.SqlStackTrace.FirstLine;
                             //方法名
                             var firstMethodName = db.Ado.SqlStackTrace.FirstMethodName;

                             //获取上层方法的信息
                             var parentFileName = db.Ado.SqlStackTrace.MyStackTraceList[1].FileName;

                             var sqlStr = string.Format("{0}:【{1}】{2}", fileName, firstMethodName, fileLine);

                             warnSqlLog?.Invoke(timeMill, sqlStr, parentFileName);
                         }
                     }
                 };

                 //SQL报错
                 db.Aop.OnError = (exp) =>
                 {
                     if (errorSqlLog != null)
                     {
                         //获取原生SQL推荐 5.1.4.63  性能OK
                         var sql = UtilMethods.GetNativeSql(exp.Sql, exp.Parametres as SugarParameter[]);

                         errorSqlLog?.Invoke(sql);
                     }
                 };

             });

            return sqlSugar;
        }
    }
}
